/*
 * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
 * Use of this source code is governed by a MIT license that can be
 * found in the LICENSE file.
 */

#include "LinearGradientComponentInstance.h"
#include <algorithm>

namespace rnoh {

constexpr float STRAIGHT_ANGLE = 180.0f;
constexpr float RIGHT_ANGLE = 90.0f;
constexpr float FULL_STOP = 1.0f;

LinearGradientComponentInstance::LinearGradientComponentInstance(Context context)
    : BaseRNLinearGradientComponentInstance(std::move(context)) {}

void LinearGradientComponentInstance::onChildInserted(ComponentInstance::Shared const &childComponentInstance,
                                                      std::size_t index) {
    Super::onChildInserted(childComponentInstance, index);
    m_stackNode.insertChild(childComponentInstance->getLocalRootArkUINode(), index);
}

void LinearGradientComponentInstance::onChildRemoved(ComponentInstance::Shared const &childComponentInstance) {
    Super::onChildRemoved(childComponentInstance);
    m_stackNode.removeChild(childComponentInstance->getLocalRootArkUINode());
};

LinearGradientStackNode &LinearGradientComponentInstance::getLocalRootArkUINode() { return m_stackNode; }

void LinearGradientComponentInstance::onPropsChanged(SharedConcreteProps const &props) {
    Super::onPropsChanged(props);
    m_colors = props->colors;
    m_angle = props->angle;
    m_useAngle = props->useAngle;
    m_locations = props->locations;
    m_startPoint = props->startPoint;
    m_endPoint = props->endPoint;
    m_angleCenter = props->angleCenter;
    this->getLinearGradient();
    this->getLocalRootArkUINode().setLinearGradient(m_colors, m_stops, static_cast<float>(m_angle),
                                                    ARKUI_LINEAR_GRADIENT_DIRECTION_CUSTOM, false);
}

void LinearGradientComponentInstance::getLinearGradient() {
    if (m_colors.size() == 0 ||
        m_locations.size() != 0 && (m_locations.size() != 0 && m_colors.size() != m_locations.size())) {
        m_angle = 0;
        return;
    }
    if (m_useAngle && m_angleCenter == facebook::react::Point{0, 0}) {
        // OH dose not support angleCenter
    } else {
        if (!m_useAngle) {
            m_angle = this->computeAngle(m_startPoint, m_endPoint);
        }
    }
    if (m_locations.size() != 0) {
        for (int index = 0; index < m_colors.size(); index++) {
            m_stops.push_back(static_cast<float>(m_locations[index]));
        }
    } else {
        this->computeStops();
    }
    return;
}

void LinearGradientComponentInstance::computeStops() {
    float startPointX = m_startPoint.x > 0 ? m_startPoint.x : 0.0;
    float startPointY = m_startPoint.y > 0 ? m_startPoint.y : 0.0;
    float endPointX = m_endPoint.x > 0 ? m_endPoint.x : 0.0;
    float endPointY = m_endPoint.y > 0 ? m_endPoint.y : 0.0;
    // 确定 pointMin 和 pointMax 值
    float pointMax = 0.0;
    float pointMin = 0.0;
    if (startPointX == endPointX) {
        pointMin = std::min(startPointY, endPointY);
        pointMax = std::max(startPointY, endPointY);
    } else if (startPointY == endPointY) {
        pointMin = std::min(startPointX, endPointX);
        pointMax = std::max(startPointX, endPointX);
    } else {
        float pointMinX = std::min(startPointX, endPointX);
        float pointMaxX = std::max(startPointX, endPointX);
        float pointMinY = std::min(startPointY, endPointY);
        float pointMaxY = std::max(startPointY, endPointY);
        pointMin = (pointMaxY - pointMinY < pointMaxX - pointMinX) ? pointMinX : pointMinY;
        pointMax = (pointMaxY - pointMinY < pointMaxX - pointMinX) ? pointMaxX : pointMaxY;
    }
    // 确定每个颜色在渐变中的分布位置
    int colorsSize = m_colors.size();
    if (colorsSize == 1) {
        m_stops.push_back(1);
    } else {
        for (int index = 0; index < colorsSize; ++index) {
            if (index == 0) {
                m_stops.push_back(pointMin);
            } else if (index == colorsSize - 1) {
                m_stops.push_back(pointMax);
            } else {
                m_stops.push_back(pointMin + index * 1.0f / (colorsSize - 1) * (pointMax - pointMin));
            }
        }
    }
}

facebook::react::Float LinearGradientComponentInstance::computeAngle(facebook::react::Point const &start,
                                                                     facebook::react::Point const &end) {
    if (start.x == end.x) {
        return (start.y < end.y) ? STRAIGHT_ANGLE : 0;
    }
    if (start.y == end.y) {
        return (start.x < end.x) ? RIGHT_ANGLE : -RIGHT_ANGLE;
    }

    float tanAngle = (end.x - start.x) / (end.y - start.y);
    return STRAIGHT_ANGLE - atan(tanAngle) * STRAIGHT_ANGLE / M_PI;
}
} // namespace rnoh